#include "SQLiteUserDAO.h"

SQLiteUserDAO::SQLiteUserDAO(sqlite3* database) {
	this->database = database;
}

void SQLiteUserDAO::save(const User& user) {
	sqlite3_stmt* statement;
	const char* sql = "insert into user values (?,?)";

	int rc = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		std::ostringstream oss;
		oss << "Error on prepare statement. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	sqlite3_bind_null(statement, 1);
	sqlite3_bind_text(statement, 2, user.getDeviceCode().c_str(), -1,
			SQLITE_STATIC);

	rc = sqlite3_step(statement);
	sqlite3_finalize(statement);
	if (rc != SQLITE_DONE) {
		std::ostringstream oss;
		oss << "Cannot save the user. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}
}

void SQLiteUserDAO::update(const User& user) {
	sqlite3_stmt* statement;
	const char* sql = "update user set device_code=? where id=?";

	int rc = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		std::ostringstream oss;
		oss << "Error on prepare statement. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	sqlite3_bind_text(statement, 1, user.getDeviceCode().c_str(), -1,
			SQLITE_STATIC);
	sqlite3_bind_int(statement, 2, user.getId());

	rc = sqlite3_step(statement);
	sqlite3_finalize(statement);
	if (rc != SQLITE_DONE) {
		std::ostringstream oss;
		oss << "Cannot update the user. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}
}

void SQLiteUserDAO::remove(const User& user) {
	sqlite3_stmt* statement;
	const char* sql = "delete from user where id=?";

	int rc = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		std::ostringstream oss;
		oss << "Error on prepare statement. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	sqlite3_bind_int(statement, 1, user.getId());

	rc = sqlite3_step(statement);
	sqlite3_finalize(statement);
	if (rc != SQLITE_DONE) {
		std::ostringstream oss;
		oss << "Cannot remove the user. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}
}

User SQLiteUserDAO::loadUserById(int id) {
	sqlite3_stmt* statement;
	const char* sql = "select * from user where id=?";

	int rc = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		std::ostringstream oss;
		oss << "Error on prepare statement. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	sqlite3_bind_int(statement, 1, id);

	rc = sqlite3_step(statement);
	if (rc != SQLITE_ROW) {
		if (rc == SQLITE_DONE)
			return User();
		std::ostringstream oss;
		oss << "Cannot load the user. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	User user(sqlite3_column_int(statement, 0),
			(const char*) sqlite3_column_text(statement, 1));
	sqlite3_finalize(statement);

	return user;
}

User SQLiteUserDAO::loadUserByDeviceCode(const string& code) {
	sqlite3_stmt* statement;
	const char* sql = "select * from user where device_code=?";

	int rc = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		std::ostringstream oss;
		oss << "Error on prepare statement. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	sqlite3_bind_text(statement, 1, code.c_str(), -1, SQLITE_STATIC);

	rc = sqlite3_step(statement);
	if (rc != SQLITE_ROW) {
		if (rc == SQLITE_DONE)
			return User();
		std::ostringstream oss;
		oss << "Cannot load the user. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	User user(sqlite3_column_int(statement, 0),
			(const char*) sqlite3_column_text(statement, 1));
	sqlite3_finalize(statement);

	return user;
}

int SQLiteUserDAO::countAll() {
	sqlite3_stmt* statement;
	const char* sql = "select count(id) from user";

	int rc = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		std::ostringstream oss;
		oss << "Error on prepare statement. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	rc = sqlite3_step(statement);
	if (rc != SQLITE_ROW) {
		std::ostringstream oss;
		oss << "Cannot count genres. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	int count = sqlite3_column_int(statement, 0);
	sqlite3_finalize(statement);

	return count;
}

